package com.l2qq.admin.account;

import cn.hutool.core.lang.Validator;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;

import com.l2qq.common.model.Account;

public class AccountTool {

    // 密码加盐 hash
    public Ret passwordSaltAndHash(Account account) {
        Ret ret = Ret.ok();
        if (StrKit.isBlank(account.getPassword())) {
            ret.setFail().set("msg", "密码不能为空");
            //throw new RuntimeException("密码不能为空");
        } else {
            //判断字符串是否全部为字母组成，包括大写和小写字母和汉字
            boolean isLetter = Validator.isLetter(account.getPassword());
            boolean isNumber = Validator.isNumber(account.getPassword());
            if (isLetter || isNumber) {
                ret.setFail().set("msg", "密码必须包含字母、数字，且6位~15位数！");
                //throw new RuntimeException("密码必须包含字母、数字，且6位~15位数！");
            }
        }

        String salt = HashKit.generateSaltForSha256();
        String pwd = account.getPassword();
        pwd = HashKit.sha256(salt + pwd);
        account.setPassword(pwd);
        account.setSalt(salt);

        return ret;
    }

    /**
     * 预处理
     * 1：去除前后空白字符
     * 2：登录名 userName 转换成小写字符（不区分大小写）
     * 3：预防 mass assignment 攻击，只保留以下必要字段
     * http://www.jfinal.com/feedback/4677
     * https://www.oschina.net/question/260040_46570
     */
    private void preProccess(Account a) {
        // 只保留必要字段，预防 mass assignment 攻击
        a.keep("id", "username", "password", "shortcut_key", "realname", "billing_company_id");
        // 移除所有空值属性，避免 account.update() 将某些字段置为 null
        //a.removeNullValueAttrs();
        // userName 转换为小写字母（不区分大小写）
        if (a.getUsername() != null) {
            a.setUsername(a.getUsername().trim().toLowerCase());
        }
        // password 去除前后空白
        if (a.getPassword() != null) {
            a.setPassword(a.getPassword().trim());
        }

        // password 去除前后空白
        if (a.getRealname() != null) {
            a.setRealname(a.getRealname().trim());
        }
    }


    /**
     * 验证
     *
     * @param create true 表示验证创建 account，否则表示验证更新 account
     */
    public Ret validate(Account account, boolean create) {
        String userName = account.getUsername();
        String password = account.getPassword();
        String nickName = account.getRealname();

        if (StrKit.isBlank(userName)) {
            return Ret.fail("msg", "手机不能为空");
        }

        // 创建
        if (create) {
            if (StrKit.isBlank(password)) {
                return Ret.fail("msg", "密码不能为空");
            }
            if (password.trim().length() < 6) {
                return Ret.fail("msg", "密码长度至少为 6");
            }
        }
        // 更新
        else {
            if (StrKit.notBlank(password) && password.trim().length() < 6) {
                return Ret.fail("msg", "密码长度至少为 6");
            }
        }

        if (StrKit.isBlank(nickName)) {
            return Ret.fail("msg", "姓名不能为空");
        }

        if (userName.contains(" ") || userName.contains("　")) { // 检测是否包含半角或全角空格
            return Ret.fail("msg", "手机(登录账号)不能包含空格");
        }
        if (nickName.contains(" ") || nickName.contains("　")) { // 检测是否包含半角或全角空格
            return Ret.fail("msg", "姓名不能包含空格");
        }

        // 创建时的 id 为 -1，用于 isUserNameExists、isNickNameExists 方法中使用
        int id = create ? -1 : account.getId();
        if (isUserNameExists(userName, id)) {
            return Ret.fail("msg", "手机(登录账号)已被注册，请换一个手机号码");
        }
/*        if (isNickNameExists(nickName, id)) {
            return Ret.fail("msg", "姓名已被注册，请修改");
        }*/

        return Ret.ok();
    }

    /**
     * 用户名是否已被注册
     * 注意：userName 被转换为小写字母后存入数据库
     */
    private boolean isUserNameExists(String userName, int selfId) {
        userName = userName.toLowerCase().trim();
        return Db.queryInt("select id from account where username = ? and id != ? limit 1", userName, selfId) != null;
    }

    /**
     * 昵称是否已被注册，昵称不区分大小写，以免存在多个用户昵称看起来一个样的情况
     * <p>
     * mysql 的 where 字句与 order by 子句默认不区分大小写，区分大小写需要在
     * 字段名或字段值前面使用 binary 关键字例如：
     * where nickName = binary "jfinal" 或者 where binary nickName = "jfinal"，前者性能要高
     * <p>
     * 为了避免不同的 mysql 配置破坏掉 mysql 的 where 不区分大小写的行为，这里在 sql 中使用
     * lower(...) 来处理，参数 nickName 也用 toLowerCase() 方法来处理，再次确保不区分大小写
     */
    private boolean isNickNameExists(String nickName, int selfId) {
        nickName = nickName.toLowerCase().trim();
        return Db.queryInt("select id from account where lower(realname) = ? and id != ? limit 1", nickName, selfId) != null;
    }
}
